use crate::egui;
use egui::{Widget, Button, vec2, Vec2, Stroke, Id, Context, InnerResponse, Ui, Rect, WidgetText, Label, Response, Pos2};
use egui_dy::eframe::egui::{RichText, Sense};
use web_time::{Duration, Instant};

pub struct IntegrateButton<'a> {
    text: &'a str,
    padding: Vec2,
}

impl<'a> IntegrateButton<'a> {
    pub fn new(text: &'a str) -> Self {
        Self { text, padding: Vec2::ZERO }
    }
    pub fn padding(self, pad: Vec2) -> Self {
        Self { padding: pad, ..self }
    }
}

impl Widget for IntegrateButton<'_> {
    fn ui(self, ui: &mut egui::Ui) -> egui::Response {
        ui.spacing_mut().item_spacing = vec2(0.0, 0.0);
        ui.spacing_mut().button_padding = self.padding;
        let button = Button::new(self.text)
            .stroke(Stroke::NONE)
            .rounding(0.0);
        ui.add(button)
    }
}

pub fn window_clicked(ctx: &Context, window: Id) -> bool {
    let mut result = false;
    let released = ctx.input(|i| i.pointer.primary_released());
    let dragging = ctx.input(|i| i.pointer.is_decidedly_dragging());
    let focused = ctx.top_layer_id().unwrap().id == window;
    if released && focused && !dragging {
        let rect = ctx.memory(|m| m.area_rect(window).unwrap());
        let pos = ctx.input(|i| i.pointer.interact_pos().unwrap());
        if rect.contains(pos) {
            result = true;
        }
    }
    result
}

pub fn child_ui<R>(ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse<R> {
    let cursor_min = ui.cursor().min;
    let rect = Rect::from_min_max(cursor_min, cursor_min);
    ui.allocate_ui_at_rect(rect, add_contents)
}

pub fn no_select_label(ui: &mut Ui, text: impl Into<WidgetText>) -> Response {
    let label = Label::new(text).selectable(false);
    ui.add(label)
}

#[derive(Debug)]
pub struct MessageRenderer {
    messages: Vec<Message>,
    show_duration: Duration,
    fade_after: Duration,
    seed_id: Id,
}
impl MessageRenderer {
    pub fn new() -> Self {
        Self { messages: Vec::new(), show_duration: Duration::from_secs(1), fade_after: Duration::from_millis(500), seed_id: Id::new("message") }
    }
    pub fn add_message(&mut self, info: String, pos: Pos2, persist: bool) {
        let message = Message::new(info, pos, persist);
        self.messages.push(message);
    }
    pub fn update(&mut self, ui: &mut Ui) {
        let now = Instant::now();
        for i in 0..self.messages.len() {
            let message = &mut self.messages[i];
            let elapsed = now - message.start;
            ui.ctx().request_repaint();
            let opacity = if elapsed >= self.fade_after {
                self.show_duration.saturating_sub(elapsed).as_millis() as f32 / 500.0
            } else {
                1.0
            };
            let frame = if message.persist {
                egui::Frame::window(ui.style())
            } else {
                egui::Frame::window(ui.style()).multiply_with_opacity(opacity)
            };
            let res = egui::Area::new(self.seed_id.with(i))
            .fixed_pos(message.pos)
            .show(ui.ctx(), |ui| {
                frame.show(ui, |ui| {
                    let text = RichText::new(&message.info).color(ui.style().visuals.text_color().linear_multiply(opacity));
                    ui.horizontal(|ui| {
                        let res = ui.label(text);
                        message.open = !ui.button("🗙").clicked();
                        res
                    }).inner
                }).inner
            });
            let res = res.inner | res.response.interact(Sense::click());
            if res.clicked() {
                message.persist = true;
            }
            if res.hovered() {
                message.start = now;
            };
            if elapsed > self.show_duration && !message.persist {
                message.open = false;
            }
        }
        self.messages.retain(|mes| mes.open);
    }
}
#[derive(Debug)]
struct Message {
    info: String,
    pos: Pos2,
    persist: bool,
    start: Instant,
    open: bool,
}
impl Message {
    fn new(info: String, pos: Pos2, persist: bool) -> Self {
        Self { info, pos, persist, start: Instant::now(), open: true }
    }
}